<script setup>
// 响应式数据
const selectedNodeId = ref(null)
const flowCanvas = ref(null)
const flowDataJson = ref('')

// 节点颜色映射
const nodeColors = ref({
  edge: '#3498db',
  main: '#2ecc71',
  global: '#e74c3c',
  source: '#9b59b6',
  default: '#7f8c8d',
})

// 默认流程图数据
const defaultFlowData = {
  nodes: [
    {
      index: 1,
      column: 0,
      name: '华南边缘分组',
      type: 'edge',
      description: '位于华南地区的边缘计算节点，负责初步数据处理和转发。',
    },
    {
      index: 2,
      column: 1,
      name: '中国主上游分组',
      type: 'main',
      description: '中国地区的主要上游节点，负责数据聚合和分发。',
    },
    {
      index: 3,
      column: 2,
      name: '全球香港',
      type: 'global',
      description: '位于香港的全球节点，提供亚太地区服务。',
    },
    {
      index: 4,
      column: 2,
      name: '中国备',
      type: 'global',
      description: '中国地区的备用节点，确保服务高可用性。',
    },
    {
      index: 5,
      column: 2,
      name: '全球美国',
      type: 'global',
      description: '位于美国的全球节点，提供美洲地区服务。',
    },
    {
      index: 6,
      column: 3,
      name: '源站',
      type: 'source',
      description: '数据源站，存储原始数据和处理逻辑。',
    },
  ],
  connections: [
    { id: 'c1', from: 1, to: 2 },
    { id: 'c2', from: 2, to: 3 },
    { id: 'c3', from: 3, to: 4 },
    { id: 'c3', from: 2, to: 4 },
    { id: 'c4', from: 2, to: 5 },
    { id: 'c6', from: 4, to: 6 },
    { id: 'c7', from: 5, to: 6 },
  ],
}

// 流程图数据
const flowData = ref(JSON.parse(JSON.stringify(defaultFlowData)))

// 节点和连接线数据
const nodes = ref([])
const connections = ref([])

// 选中的节点
const selectedNode = ref(null)

// 节点类型名称映射
const nodeTypeNames = {
  edge: '边缘节点',
  main: '主上游节点',
  global: '全球节点',
  source: '源站',
  default: '默认节点',
}

// 初始化数据
function initializeData() {
  flowDataJson.value = JSON.stringify(flowData.value, null, 2)
  calculateLayout()
}

// 计算布局
function calculateLayout() {
  const canvasWidth = flowCanvas.value ? flowCanvas.value.offsetWidth : 800
  const canvasHeight = flowCanvas.value ? flowCanvas.value.offsetHeight : 500

  // 重置节点位置
  nodes.value = flowData.value.nodes.map(node => ({
    ...node,
    x: 0,
    y: 0,
  }))

  // 根据布局类型计算节点位置
  calculateHorizontalLayout(canvasWidth, canvasHeight)

  // 更新连接线
  updateConnections()
}

// 改进的布局计算
function calculateHorizontalLayout(width, height) {
  const columns = {}

  // 按列分组
  flowData.value.nodes.forEach((node) => {
    const column = node.column
    if (!columns[column])
      columns[column] = []
    columns[column].push(node)
  })

  // 计算每列的位置
  Object.keys(columns).forEach((column) => {
    const nodesInColumn = columns[column]
    const columnHeight = height
    const startY = height * 0.1
    const spacing = columnHeight / (nodesInColumn.length + 1)

    nodesInColumn.forEach((node, index) => {
      const nodeIndex = nodes.value.findIndex(n => n.index === node.index)
      if (nodeIndex !== -1) {
        nodes.value[nodeIndex].x
          = width * 0.1
            + column * ((width * 0.8) / (Object.keys(columns).length - 1))
            - 70
        nodes.value[nodeIndex].y = startY + spacing * (index + 1) - 15

        // 记录节点在列中的位置信息
        nodes.value[nodeIndex].columnIndex = index
        nodes.value[nodeIndex].totalInColumn = nodesInColumn.length
      }
    })
  })
}

// 改进的90°折线路径计算
function calculate90DegreePath(start, end, fromNode, toNode) {
  const points = [start]
  const safeMargin = 100

  const fromRight = fromNode.x + 140
  const fromLeft = fromNode.x
  const fromTop = fromNode.y
  const fromBottom = fromNode.y + 30

  const toRight = toNode.x + 140
  const toTop = toNode.y
  const toBottom = toNode.y + 30

  const startFromRight = Math.abs(start.x - fromRight) < 5
  const startFromLeft = Math.abs(start.x - fromLeft) < 5
  const startFromTop = Math.abs(start.y - fromTop) < 5
  const startFromBottom = Math.abs(start.y - fromBottom) < 5

  const endAtRight = Math.abs(end.x - toRight) < 5
  const endAtTop = Math.abs(end.y - toTop) < 5
  const endAtBottom = Math.abs(end.y - toBottom) < 5

  const addPoint = (x, y) => points.push({ x, y })

  // 情况1: 从右侧出发，到达底部
  if (startFromRight && endAtBottom) {
    const targetBottomCenterX = toNode.x + 70
    addPoint(targetBottomCenterX, start.y)
    addPoint(targetBottomCenterX, end.y + safeMargin)
    addPoint(targetBottomCenterX, end.y + safeMargin)
    addPoint(end.x, end.y)
  } else if (startFromRight && endAtTop) {
    // 情况2: 从右侧出发，到达顶部
    addPoint(start.x + safeMargin, start.y)
    addPoint(start.x + safeMargin, end.y - safeMargin)
    addPoint(end.x, end.y - safeMargin)
    addPoint(end.x, end.y)
  } else if (startFromBottom && endAtRight) {
    // 情况3: 从底部出发，到达右侧
    addPoint(start.x, start.y + safeMargin)
    addPoint(end.x + safeMargin, start.y + safeMargin)
    addPoint(end.x + safeMargin, end.y)
    addPoint(end.x, end.y)
  } else if (startFromTop && endAtRight) {
    // 情况4: 从顶部出发，到达右侧
    addPoint(start.x, start.y - safeMargin)
    addPoint(end.x + safeMargin, start.y - safeMargin)
    addPoint(end.x + safeMargin, end.y)
    addPoint(end.x, end.y)
  } else if (startFromLeft && endAtBottom) {
    // 情况5: 从左侧出发，到达底部
    addPoint(start.x - safeMargin, start.y)
    addPoint(start.x - safeMargin, end.y + safeMargin)
    addPoint(end.x, end.y + safeMargin)
    addPoint(end.x, end.y)
  } else if (startFromLeft && endAtTop) {
    // 情况6: 从左侧出发，到达顶部
    addPoint(start.x - safeMargin, start.y)
    addPoint(start.x - safeMargin, end.y - safeMargin)
    addPoint(end.x, end.y - safeMargin)
    addPoint(end.x, end.y)
  } else {
    // 默认情况：基于相对位置的一般路径
    const isToRight = end.x > start.x
    const isToLeft = end.x < start.x
    const isToBottom = end.y > start.y
    const isToTop = end.y < start.y

    if (isToRight && isToBottom) {
      const midX = end.x - safeMargin
      addPoint(midX, start.y)
      addPoint(midX, end.y)
    } else if (isToRight && isToTop) {
      const midX = end.x - safeMargin
      addPoint(midX, start.y)
      addPoint(midX, end.y)
    } else if (isToLeft && isToBottom) {
      const midX = end.x + safeMargin
      addPoint(midX, start.y)
      addPoint(midX, end.y)
    } else if (isToLeft && isToTop) {
      const midX = end.x + safeMargin
      addPoint(midX, start.y)
      addPoint(midX, end.y)
    } else if (isToRight) {
      const midX = (start.x + end.x) / 2
      addPoint(midX, start.y)
      addPoint(midX, end.y)
    } else if (isToLeft) {
      const midX = (start.x + end.x) / 2
      addPoint(midX, start.y)
      addPoint(midX, end.y)
    } else if (isToBottom) {
      const midY = (start.y + end.y) / 2
      addPoint(start.x, midY)
      addPoint(end.x, midY)
    } else if (isToTop) {
      const midY = (start.y + end.y) / 2
      addPoint(start.x, midY)
      addPoint(end.x, midY)
    }
    addPoint(end.x, end.y)
  }
  return points
}
// 改进的连接点计算逻辑
function updateConnections() {
  connections.value = flowData.value.connections
    .map((conn) => {
      const fromNode = nodes.value.find(n => n.index === conn.from)
      const toNode = nodes.value.find(n => n.index === conn.to)

      if (!fromNode || !toNode)
        return null

      // 获取节点的边界坐标
      const fromLeft = fromNode.x
      const fromRight = fromNode.x + 140
      const fromTop = fromNode.y
      const fromBottom = fromNode.y + 30
      const fromCenterX = fromNode.x + 70
      const fromCenterY = fromNode.y + 15

      const toLeft = toNode.x
      const toRight = toNode.x + 140
      const toTop = toNode.y
      const toBottom = toNode.y + 30
      const toCenterX = toNode.x + 70
      const toCenterY = toNode.y + 15

      // 智能选择最佳的连接点
      let startPoint, endPoint

      // 根据节点的列位置和相对位置选择最佳连接点
      if (toNode.column > fromNode.column) {
        // 目标在右侧
        if (toNode.columnIndex > fromNode.columnIndex) {
          // 目标在右下方 - 优先从右侧出发，根据具体情况选择终点
          startPoint = { x: fromRight, y: fromCenterY }
          // 如果目标在同一列或相邻列，连接到左侧；否则连接到最合适的位置
          if (toNode.column - fromNode.column === 1) {
            endPoint = { x: toLeft, y: toCenterY }
          } else {
            // 跨多列连接，优先连接到底部
            endPoint = { x: toCenterX, y: toBottom }
          }
        } else {
          // 目标在右上方
          startPoint = { x: fromRight, y: fromCenterY }
          if (toNode.column - fromNode.column === 1) {
            endPoint = { x: toLeft, y: toCenterY }
          } else {
            endPoint = { x: toCenterX, y: toTop }
          }
        }
      } else if (toNode.column < fromNode.column) {
        // 目标在左侧
        if (toNode.columnIndex > fromNode.columnIndex) {
          // 目标在左下方
          startPoint = { x: fromLeft, y: fromCenterY }
          if (fromNode.column - toNode.column === 1) {
            endPoint = { x: toRight, y: toCenterY }
          } else {
            endPoint = { x: toCenterX, y: toBottom }
          }
        } else {
          // 目标在左上方
          startPoint = { x: fromLeft, y: fromCenterY }
          if (fromNode.column - toNode.column === 1) {
            endPoint = { x: toRight, y: toCenterY }
          } else {
            endPoint = { x: toCenterX, y: toTop }
          }
        }
      } else {
        // 同一列
        if (toNode.columnIndex > fromNode.columnIndex) {
          // 目标在下方
          startPoint = { x: fromCenterX, y: fromBottom }
          endPoint = { x: toCenterX, y: toTop }
        } else {
          // 目标在上方
          startPoint = { x: fromCenterX, y: fromTop }
          endPoint = { x: toCenterX, y: toBottom }
        }
      }

      // 特殊处理：全球美国(5)到源站(6)的连接
      if (conn.from === 5 && conn.to === 6) {
        startPoint = { x: fromRight, y: fromCenterY } // 从右侧出发
        endPoint = { x: toCenterX, y: toBottom } // 连接到底部
      }

      // 计算90°折线路径
      const points = calculate90DegreePath(
        startPoint,
        endPoint,
        fromNode,
        toNode,
      )

      return {
        ...conn,
        fromX: startPoint.x,
        fromY: startPoint.y,
        toX: endPoint.x,
        toY: endPoint.y,
        type: 'polyline',
        points,
      }
    })
    .filter(conn => conn !== null)
}
// 获取连接线样式
function getConnectionStyle(connection) {
  if (connection.type === 'straight') {
    // 直线连接
    const dx = connection.toX - connection.fromX
    const dy = connection.toY - connection.fromY
    const length = Math.sqrt(dx * dx + dy * dy)
    const angle = (Math.atan2(dy, dx) * 180) / Math.PI

    return {
      left: `${connection.fromX}px`,
      top: `${connection.fromY}px`,
      width: `${length}px`,
      transform: `rotate(${angle}deg)`,
    }
  } else {
    // 折线连接 - 使用SVG路径
    return {
      left: '0',
      top: '0',
      width: '100%',
      height: '100%',
      transform: 'none',
    }
  }
}

// 选择节点
function selectNode(nodeId) {
  selectedNodeId.value = nodeId
  selectedNode.value = nodes.value.find(node => node.index === nodeId)
}

// 获取节点类型名称
function getNodeTypeName(type) {
  return nodeTypeNames[type] || nodeTypeNames.default
}

// 应用数据
function applyData() {
  try {
    const newData = JSON.parse(flowDataJson.value)
    flowData.value = newData
    calculateLayout()
  } catch (e) {
    console('数据格式错误，请检查JSON格式', e)
  }
}

// 重置数据
function resetData() {
  flowData.value = JSON.parse(JSON.stringify(defaultFlowData))
  initializeData()
}

// 导出为图片
function exportAsImage() {
  if (!flowCanvas.value)
    return

  // 创建一个临时画布来绘制流程图
  const canvas = document.createElement('canvas')
  const ctx = canvas.getContext('2d')

  // 设置画布尺寸
  canvas.width = flowCanvas.value.scrollWidth
  canvas.height = flowCanvas.value.scrollHeight

  // 绘制白色背景
  ctx.fillStyle = 'white'
  ctx.fillRect(0, 0, canvas.width, canvas.height)

  // 绘制节点
  nodes.value.forEach((node) => {
    // 绘制节点矩形
    ctx.fillStyle = nodeColors.value[node.type] || nodeColors.value.default
    ctx.fillRect(node.x, node.y, 140, 30)

    // 绘制边框
    ctx.strokeStyle = '#2c3e50'
    ctx.lineWidth = 1
    ctx.strokeRect(node.x, node.y, 140, 30)

    // 绘制圆角
    ctx.beginPath()
    ctx.roundRect(node.x, node.y, 140, 30, 8)
    ctx.stroke()

    // 绘制文字
    ctx.fillStyle = 'white'
    ctx.font = 'bold 14px Arial'
    ctx.textAlign = 'center'
    ctx.textBaseline = 'middle'
    ctx.fillText(node.name, node.x + 70, node.y + 15)
  })

  // 绘制连接线
  connections.value.forEach((conn) => {
    ctx.strokeStyle = '#4a6491'
    ctx.lineWidth = 1

    if (conn.type === 'straight') {
      // 绘制直线
      ctx.beginPath()
      ctx.moveTo(conn.fromX, conn.fromY)
      ctx.lineTo(conn.toX, conn.toY)
      ctx.stroke()
    } else {
      // 绘制折线
      ctx.beginPath()
      ctx.moveTo(conn.points[0].x, conn.points[0].y)
      for (let i = 1; i < conn.points.length; i++) {
        ctx.lineTo(conn.points[i].x, conn.points[i].y)
      }
      ctx.stroke()
    }

    // 绘制箭头
    const lastPoint = conn.points[conn.points.length - 1]
    const prevPoint = conn.points[conn.points.length - 2]
    const angle = Math.atan2(
      lastPoint.y - prevPoint.y,
      lastPoint.x - prevPoint.x,
    )

    ctx.fillStyle = '#4a6491'
    ctx.beginPath()
    ctx.moveTo(lastPoint.x, lastPoint.y)
    ctx.lineTo(
      lastPoint.x - 10 * Math.cos(angle - Math.PI / 6),
      lastPoint.y - 10 * Math.sin(angle - Math.PI / 6),
    )
    ctx.lineTo(
      lastPoint.x - 10 * Math.cos(angle + Math.PI / 6),
      lastPoint.y - 10 * Math.sin(angle + Math.PI / 6),
    )
    ctx.closePath()
    ctx.fill()
  })

  // 创建下载链接
  const a = document.createElement('a')
  a.download = 'flow-diagram.png'
  a.href = canvas.toDataURL('image/png')
  a.click()
}

// 监听画布尺寸变化
onMounted(() => {
  initializeData()

  // 响应窗口大小变化
  window.addEventListener('resize', calculateLayout)
})
</script>

<template>
  <div class="container">
    <div class="controls">
      <button @click="exportAsImage">
        导出为图片
      </button>
      <button @click="resetData">
        重置数据
      </button>
    </div>

    <div class="flow-container">
      <div
        ref="flowCanvas"
        class="flow-canvas"
      >
        <!-- 动态生成的节点 -->
        <div
          v-for="node in nodes"
          :key="node.index"
          class="flow-node"
          :class="[
            `node-type-${node.type}`,
            { selected: selectedNodeId === node.index },
          ]"
          :style="{
            left: `${node.x}px`,
            top: `${node.y}px`,
            backgroundColor: nodeColors[node.type],
          }"
          @click="selectNode(node.index)"
        >
          {{ node.name }}
        </div>

        <!-- 动态生成的连接线 -->
        <template
          v-for="connection in connections"
          :key="connection.id"
        >
          <div
            v-if="connection.type === 'straight'"
            class="flow-connection straight"
            :style="getConnectionStyle(connection)"
          />
          <svg
            v-else-if="connection.type === 'polyline'"
            class="flow-connection polyline"
            style="
              position: absolute;
              left: 0;
              top: 0;
              width: 100%;
              height: 100%;
              pointer-events: none;
              z-index: 1;
            "
          >
            <defs>
              <marker
                id="arrowhead"
                markerWidth="10"
                markerHeight="7"
                refX="9"
                refY="3.5"
                orient="auto"
              >
                <polygon
                  points="0 0, 10 3.5, 0 7"
                  fill="#4a6491"
                />
              </marker>
            </defs>
            <polyline
              :points="connection.points.map(p => `${p.x},${p.y}`).join(' ')"
              fill="none"
              stroke="#4a6491"
              stroke-width="2"
              stroke-dasharray="5,2"
              marker-end="url(#arrowhead)"
            />
          </svg>
        </template>
      </div>
    </div>
    <div
      v-if="selectedNode"
      class="node-info"
    >
      <h3>{{ selectedNode.name }}</h3>
      <p>{{ selectedNode.description || '暂无描述信息' }}</p>
      <p><strong>类型:</strong> {{ getNodeTypeName(selectedNode.type) }}</p>
      <p><strong>ID:</strong> {{ selectedNode.index }}</p>
    </div>

    <div class="data-editor">
      <h3>流程图数据编辑</h3>
      <textarea
        v-model="flowDataJson"
        placeholder="在此编辑流程图数据..."
      />
      <button
        style="margin-top: 10px; width: 100%"
        @click="applyData"
      >
        应用数据
      </button>
    </div>
  </div>
</template>

<style>
.container {
  padding: 20px;
  display: flex;
  flex-direction: column;
  height: 700px;
}
.controls {
  display: flex;
  gap: 15px;
  margin-bottom: 20px;
  flex-wrap: wrap;
  justify-content: center;
}
button {
  padding: 10px 20px;
  border: none;
  border-radius: 6px;
  background: #4a6491;
  color: white;
  cursor: pointer;
  transition: all 0.3s;
  font-weight: 500;
}
button:hover {
  background: #3a5379;
  transform: translateY(-2px);
}
button.active {
  background: #2c3e50;
  box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
}
.flow-container {
  flex: 1;
  border: 1px solid #eaeaea;
  border-radius: 8px;
  background: #fafafa;
  padding: 20px;
  position: relative;
}
.flow-canvas {
  position: relative;
  width: 100%;
  height: 100%;
  min-height: 600px;
}
.flow-node {
  position: absolute;
  border-radius: 8px;
  padding: 12px 16px;
  min-width: 140px;
  text-align: center;
  font-weight: bold;
  color: white;
  box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
  cursor: pointer;
  transition: all 0.3s;
  z-index: 2;
  border: 2px solid transparent;
}
.flow-node:hover {
  transform: translateY(-2px);
  box-shadow: 0 6px 12px rgba(0, 0, 0, 0.15);
}
.flow-node.selected {
  border-color: #2c3e50;
  box-shadow: 0 6px 12px rgba(0, 0, 0, 0.2);
  z-index: 3;
}
.flow-connection.straight {
  position: absolute;
  height: 2px;
  background: #4a6491;
  z-index: 1;
  transform-origin: 0 0;
}
.flow-connection.straight::after {
  content: '';
  position: absolute;
  right: -8px;
  top: -3px;
  width: 0;
  height: 0;
  border-left: 8px solid #4a6491;
  border-top: 4px solid transparent;
  border-bottom: 4px solid transparent;
}
.flow-connection.polyline {
  z-index: 1;
}
.node-info {
  margin-top: 20px;
  padding: 15px;
  background: #f0f4f8;
  border-radius: 8px;
  width: 100%;
  max-width: 500px;
  text-align: center;
  align-self: center;
}
.node-info h3 {
  color: #2c3e50;
  margin-bottom: 10px;
}
.node-info p {
  color: #4a6491;
  line-height: 1.5;
}

.data-editor {
  margin-top: 20px;
  padding: 15px;
  background: #f9f9f9;
  border-radius: 8px;
  width: 100%;
  max-width: 500px;
  align-self: center;
}
.data-editor h3 {
  color: #2c3e50;
  margin-bottom: 10px;
  text-align: center;
}
textarea {
  width: 100%;
  height: 120px;
  padding: 10px;
  border: 1px solid #ddd;
  border-radius: 4px;
  resize: vertical;
  font-family: monospace;
}

/* 响应式设计 */
@media (max-width: 768px) {
  .container {
    padding: 15px;
    height: 60vh;
  }
  .controls {
    flex-direction: column;
    align-items: center;
  }
  button {
    width: 100%;
    max-width: 250px;
  }
  .flow-node {
    min-width: 120px;
    font-size: 14px;
    padding: 8px 12px;
  }
}
</style>
